<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="DHN7A" id="DHN7A"><span data-lake-id="uacdb35b3" id="uacdb35b3">典型回答</span></h1>
  <p data-lake-id="u5d24d644" id="u5d24d644"><br></p>
  <p data-lake-id="ub8e4aa74" id="ub8e4aa74"><span data-lake-id="u811e96a3" id="u811e96a3">假设有一个电商下单链路，上下游一共有5个系统，分别包括了订单系统、库存系统、积分系统、邮件通知系统、以及外部机构系统。</span></p>
  <p data-lake-id="u7e2017e1" id="u7e2017e1"><span data-lake-id="ufc41bcc5" id="ufc41bcc5">​</span><br></p>
  <p data-lake-id="u2ef36775" id="u2ef36775"><span data-lake-id="u817a1a8c" id="u817a1a8c">下单的时候，订单系统需要创建订单，库存系统需要扣减库存，积分系统需要给用户增加积分，邮件通知系统需要通知用户下单成功，外部机构系统给用户投保一笔运费险。</span></p>
  <p data-lake-id="u3b3b2ca8" id="u3b3b2ca8"><span data-lake-id="u0e1d1332" id="u0e1d1332">​</span><br></p>
  <p data-lake-id="ue92261c3" id="ue92261c3"><span data-lake-id="uadcf8ef2" id="uadcf8ef2">那么， 我们需要设计一个完整的一致性方案，该怎么做呢？</span></p>
  <p data-lake-id="u958712a9" id="u958712a9"><span data-lake-id="u137a1add" id="u137a1add">​</span><br></p>
  <p data-lake-id="uf7f6471c" id="uf7f6471c"><span data-lake-id="ud4f6da8f" id="ud4f6da8f">其实这个问题考察的就是分布式事务的运用。</span></p>
  <p data-lake-id="u5dfecfa8" id="u5dfecfa8"><span data-lake-id="u1c21f822" id="u1c21f822">​</span><br></p>
  <p data-lake-id="u10769686" id="u10769686"><br></p>
  <p data-lake-id="u3801438b" id="u3801438b"><span data-lake-id="u36ee8d36" id="u36ee8d36">常见的分布式事务有XA（2PC、3PC）、TCC、Seata、可靠消息最终一致性（本地消息表、MQ事务消息）、最大努力通知等，那么该如何在实际场景中选择具体哪种方案呢？</span></p>
  <p data-lake-id="u1f8216a5" id="u1f8216a5"><span data-lake-id="u07e76503" id="u07e76503">​</span><br></p>
  <p data-lake-id="u62a81142" id="u62a81142"><span data-lake-id="u665e13dd" id="u665e13dd">首先，我们看一下订单系统、库存系统、积分系统、邮件通知系统、以及外部机构系统这五个系统对一致性的要求。</span></p>
  <p data-lake-id="u5a7b6e64" id="u5a7b6e64"><span data-lake-id="u40f03539" id="u40f03539">​</span><br></p>
  <p data-lake-id="u82905ae1" id="u82905ae1"><span data-lake-id="u1aa45245" id="u1aa45245">为啥不都考虑强一致性呢？这样就可以保证数据一定一致，没什么隐患。</span></p>
  <p data-lake-id="u8ca13860" id="u8ca13860"><span data-lake-id="u676578f4" id="u676578f4">​</span><br></p>
  <p data-lake-id="u566ea97c" id="u566ea97c"><span data-lake-id="ub6d31dd5" id="ub6d31dd5">但是这样做成本太高了，也会让下单的成功率大大降低。我们想一想，在下单环节中，是不是只要订单创建成功、库存扣减成功，是不是就可以认为下单成功了。而至于其他的邮件通知、积分增加、其实是不应该影响到用户的下单流程的。我们不能说因为给你加积分失败了，所以下单就失败了吧。</span></p>
  <p data-lake-id="udf075df1" id="udf075df1"><span data-lake-id="u00d06f5c" id="u00d06f5c">​</span><br></p>
  <p data-lake-id="u2054844c" id="u2054844c"><span data-lake-id="u045f9045" id="u045f9045">所以，我们需要区别对待。那么就需要分析一下这些系统之间的一致性要求。</span></p>
  <p data-lake-id="u5d2aec61" id="u5d2aec61"><span data-lake-id="u66e87aff" id="u66e87aff">​</span><br></p>
  <p data-lake-id="u9942db50" id="u9942db50"><span data-lake-id="u57089d9a" id="u57089d9a">首先，订单系统和库存系统，这两个基本上是要求强一致性的，因为下单成功、库存必须扣减成功，否则就会超卖。库存扣减成功，订单也一定要创建成功，否则就会少卖。</span></p>
  <p data-lake-id="u76f11bc5" id="u76f11bc5"><span data-lake-id="u59d15198" id="u59d15198">​</span><br></p>
  <p data-lake-id="uf5a06341" id="uf5a06341"><span data-lake-id="u0c160a04" id="u0c160a04">所以，订单系统和库存系统对一致性的要求很高，基本上是强一致性的。</span></p>
  <p data-lake-id="uf2352a37" id="uf2352a37"><span data-lake-id="u55591f4b" id="u55591f4b">​</span><br></p>
  <p data-lake-id="ud9eb1a0e" id="ud9eb1a0e"><span data-lake-id="u79cb2e7f" id="u79cb2e7f">订单系统和积分系统之间的一致性要求是其次的， 因为首先我们要保障下单成功后积分增加一定要成功，但是并不要求一定要做到非常的实时，稍微有一点系统延迟，其实也是可以的。</span></p>
  <p data-lake-id="u80231975" id="u80231975"><span data-lake-id="u8bd1787e" id="u8bd1787e">​</span><br></p>
  <p data-lake-id="ucc2821b3" id="ucc2821b3"><span data-lake-id="uc54c139e" id="uc54c139e">订单系统和邮件通知系统之间的一致性要求就更弱了，用户下单成功后，发送邮件通知这个动作，其实即使是丢了，对订单以及用户体验来说，其实影响并不大。</span></p>
  <p data-lake-id="u007d4d35" id="u007d4d35"><span data-lake-id="u3ba29710" id="u3ba29710">​</span><br></p>
  <p data-lake-id="u771b1012" id="u771b1012"><span data-lake-id="u0c4c0ed5" id="u0c4c0ed5">而订单系统和外部机构系统之间的这个一致性保障的话就比较特殊了，按理来说其实是很高的，订单创建成功之后，运费险一定要投保成功，但是实际在技术实现上可以做一些特殊的设计，这个我们后面讲。</span></p>
  <p data-lake-id="uf4a62d7b" id="uf4a62d7b"><br></p>
  <p data-lake-id="ufbeff17e" id="ufbeff17e"><span data-lake-id="u411c28b5" id="u411c28b5">在分析完了以上几个系统之间的一致性要求之后，我们就可以具体的做方案的设计了。（以上分析并不绝对，不同的系统之间并不一样，有的电商对于积分增加要求不高，但是对于邮件通知要求高，所以，实际需要根据业务来确定。）</span></p>
  <p data-lake-id="u1dc22007" id="u1dc22007"><span data-lake-id="ub02aec8e" id="ub02aec8e">​</span><br></p>
  <p data-lake-id="uddbc96cc" id="uddbc96cc"><span data-lake-id="u294b4b05" id="u294b4b05">首先，订单和库存系统，基本上就是要强一致性，所以，可选的方案就是XA以及TCC，也就是需要通过协调者来整体控制系统之间的数据的一致性，做到要么都成功，要么都失败。</span></p>
  <p data-lake-id="u1e8214a0" id="u1e8214a0"><span data-lake-id="uf1cae183" id="uf1cae183">​</span><br></p>
  <p data-lake-id="u4cd379f8" id="u4cd379f8"><br></p>
  <p data-lake-id="u2bb594ed" id="u2bb594ed"><span data-lake-id="u508871c8" id="u508871c8">接下来订单系统和积分系统之间，我们其实可以考虑基于可靠消息实现最终一致性，因为他要求消息不能丢，并且可以接受延迟。所以可以给予MQ事务消息，或者本地消息表来实现。</span></p>
  <p data-lake-id="u575841d8" id="u575841d8"><span data-lake-id="u2b2d73ac" id="u2b2d73ac">​</span><br></p>
  <p data-lake-id="udbb7da4f" id="udbb7da4f"><br></p>
  <p data-lake-id="u11a22eb9" id="u11a22eb9"><span data-lake-id="ude928f3a" id="ude928f3a">订单系统和邮件通知系统之间，我们就可以更加简单一点，用一个最大努力通知就行了，就算失败了也没关系。</span></p>
  <p data-lake-id="ue145354e" id="ue145354e"><span data-lake-id="u6d010a01" id="u6d010a01">​</span><br></p>
  <p data-lake-id="u90a27062" id="u90a27062"><br></p>
  <p data-lake-id="u1d1beb2c" id="u1d1beb2c"><span data-lake-id="u77b24e86" id="u77b24e86">最后，至于订单系统和外部机构系统之间，理论上是要保证强一致性的，或者说怎么也得是秒级别的最终一致性。</span></p>
  <p data-lake-id="u5ad16d5f" id="u5ad16d5f"><span data-lake-id="u839c9439" id="u839c9439">​</span><br></p>
  <p data-lake-id="u37162937" id="u37162937"><span data-lake-id="u35d60a1f" id="u35d60a1f">但是实际情况是，外部机构的可用性和电商平台的可用性是完全天差地别的。很容易在投保的过程中失败，所以，这个地方一般的做法都是在协议上约定：</span></p>
  <p data-lake-id="ue9262450" id="ue9262450"><span data-lake-id="u5e73f42d" id="u5e73f42d">​</span><br></p>
  <p data-lake-id="u2660f93f" id="u2660f93f"><span data-lake-id="u9a9d248c" id="u9a9d248c">1、只要风控通过，投保一定成功。</span></p>
  <p data-lake-id="u57e1a1be" id="u57e1a1be"><span data-lake-id="ua18b71da" id="ua18b71da">2、可以先资金流理赔，然后再补齐信息流。</span></p>
  <p data-lake-id="u56721409" id="u56721409"><span data-lake-id="u21ca2cc3" id="u21ca2cc3">​</span><br></p>
  <p data-lake-id="ua7bcd656" id="ua7bcd656"><span data-lake-id="ub36f25f6" id="ub36f25f6">有了以上的约定之后，我们就可以把和外部系统之间的交互完全做成异步，基本上都是通过离线文件，每天同步一次，把当天的投保数据和理赔数据同步过去就可以了。</span></p>
  <p data-lake-id="ucd6104c8" id="ucd6104c8"><span data-lake-id="u13030c44" id="u13030c44">​</span><br></p>
  <p data-lake-id="u9b720d64" id="u9b720d64"><span data-lake-id="ueb9ebdd0" id="ueb9ebdd0">以上，就是一个基于实际业务场景，来选择分布式事务的方案的例子，这里面没提Seata的方案，其实Seata他并不是一个方案，其实是一堆方案的组合，因为他支持很多种模式，所以，以上的方案来说，也可以整体换成Seata，但是Seata的方案其实还是比较重的，所以一般小公司用的不多。但是如果要用的话，确实也是很好很强大方案。</span></p>
  <p data-lake-id="ue0926b71" id="ue0926b71"><span data-lake-id="u0521f9ef" id="u0521f9ef">​</span><br></p>
 </body>
</html>